package com.roncoo.pay.trade.utils.alipay.util.httpClient;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.util.EntityUtils;

/* *
 *类名：HttpProtocolHandler
 *功能：HttpClient方式访问
 *详细：获取远程HTTP数据
 *版本：3.3
 *日期：2012-08-17
 *说明：
 *以下代码只是为了方便商户测试而提供的样例代码，商户可以根据自己网站的需要，按照技术文档编写,并非一定要使用该代码。
 *该代码仅供学习和研究支付宝接口使用，只是提供一个参考。
 */

public class HttpProtocolHandler {

	private static String DEFAULT_CHARSET = "UTF-8";

	/** 连接超时时间，由bean factory设置，缺省为8秒钟 */
	private int defaultConnectionTimeout = 8000;

	/** 回应超时时间, 由bean factory设置，缺省为30秒钟 */
	private int defaultSoTimeout = 30000;

	/** 闲置连接超时时间, 由bean factory设置，缺省为60秒钟 */
	private int defaultIdleConnTimeout = 60000;

	private int defaultMaxConnPerHost = 30;

	private int defaultMaxTotalConn = 80;

	/** 默认等待HttpConnectionManager返回连接超时（只有在达到最大连接数时起作用）：1秒 */
	private static final long defaultHttpConnectionManagerTimeout = 3 * 1000;
	
	private static RequestConfig config = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD_STRICT).build();

	/**
	 * HTTP连接管理器，该连接管理器必须是线程安全的.
	 */
	private static PoolingHttpClientConnectionManager connectionManager;

	private static HttpProtocolHandler httpProtocolHandler = new HttpProtocolHandler();

	/**
	 * 工厂方法
	 * 
	 * @return
	 */
	public static HttpProtocolHandler getInstance() {
		return httpProtocolHandler;
	}

	/**
	 * 私有的构造方法
	 */
	private HttpProtocolHandler() {
		Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
				.register("https", SSLConnectionSocketFactory.getSocketFactory())
				.register("http", PlainConnectionSocketFactory.getSocketFactory()).build();
		
		// 创建一个线程安全的HTTP连接池
		connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
		connectionManager.setDefaultMaxPerRoute(defaultMaxConnPerHost);
		connectionManager.setMaxTotal(defaultMaxTotalConn);
	}

	public static CloseableHttpClient getHttpClient() {
		CookieStore cookieStore = new BasicCookieStore();
		BasicClientCookie cookie = new BasicClientCookie("sessionID", "######");
		cookie.setDomain("#####");
		cookie.setPath("/");
		cookieStore.addCookie(cookie);
		CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager)
				.setDefaultCookieStore(cookieStore).setDefaultRequestConfig(config).build();
		return httpClient;
	}

	/**
	 * 执行Http请求
	 * 
	 * @param request
	 *            请求数据
	 * @param strParaFileName
	 *            文件类型的参数名
	 * @param strFilePath
	 *            文件路径
	 * @return
	 * @throws HttpException,
	 *             IOException
	 */
	public HttpResponse execute(HttpRequest request, String strParaFileName, String strFilePath)
			throws HttpException, IOException {
		CloseableHttpClient httpclient = getHttpClient();

		// 设置连接超时
		int connectionTimeout = defaultConnectionTimeout;
		if (request.getConnectionTimeout() > 0) {
			connectionTimeout = request.getConnectionTimeout();
		}
		//httpclient.getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout);

		// 设置回应超时
		int soTimeout = defaultSoTimeout;
		if (request.getTimeout() > 0) {
			soTimeout = request.getTimeout();
		}
		//httpclient.getHttpConnectionManager().getParams().setSoTimeout(soTimeout);

		// 设置等待ConnectionManager释放connection的时间
		//httpclient.getParams().setConnectionManagerTimeout(defaultHttpConnectionManagerTimeout);

		String charset = request.getCharset();
		charset = charset == null ? DEFAULT_CHARSET : charset;
		CloseableHttpResponse response2;
		// get模式且不带上传文件
		if (request.getMethod().equals(HttpRequest.METHOD_GET)) {
			HttpGet httpget = new HttpGet(request.getUrl());
			// parseNotifyConfig会保证使用GET方法时，request一定使用QueryString
			httpget.setURI(URI.create(httpget.getURI() + "?" + request.getQueryString()));
			response2 = httpclient.execute(httpget);
		} else if (strParaFileName.equals("") && strFilePath.equals("")) {
			// post模式且不带上传文件
			HttpPost httpPost = new HttpPost(request.getUrl());
			httpPost.setEntity(new UrlEncodedFormEntity(request.getParameters(), DEFAULT_CHARSET)); 
			httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded; text/html; charset=" + charset);
			response2 = httpclient.execute(httpPost);
		} else {
			// post模式且带上传文件
			HttpPost httpPost = new HttpPost(request.getUrl());
			List<ContentBody> parts = new ArrayList<ContentBody>();
			MultipartEntityBuilder builder = MultipartEntityBuilder.create();
			for (int i = 0; i < request.getParameters().size(); i++) {
				StringBody comment = new StringBody(request.getParameters().get(i).getValue(), ContentType.TEXT_PLAIN);
				builder.addPart(request.getParameters().get(i).getName(), comment);
			}
			
			// 增加文件参数，strParaFileName是参数名，使用本地文件
			builder.addPart(strParaFileName, new FileBody(new File(strFilePath)));
			HttpEntity httpEntity = builder.build();
			httpPost.setEntity(httpEntity);
			httpPost.addHeader("User-Agent", "Mozilla/4.0");
			response2 = httpclient.execute(httpPost);
		}

		// 设置Http Header中的User-Agent属性
		
		HttpResponse response = new HttpResponse();
		
		try {
			if (request.getResultType().equals(HttpResultType.STRING)) {
				HttpEntity resEntity = response2.getEntity();
				response.setStringResult(EntityUtils.toString(resEntity));
				EntityUtils.consume(resEntity);
			} else if (request.getResultType().equals(HttpResultType.BYTES)) {
				HttpEntity resEntity = response2.getEntity();
				response.setByteResult(EntityUtils.toByteArray(resEntity));
				EntityUtils.consume(resEntity);
			}
			HttpEntity resEntity = response2.getEntity();
			response.setResponseHeaders(response2.getAllHeaders());
		} catch (UnknownHostException ex) {

			return null;
		} catch (IOException ex) {

			return null;
		} catch (Exception ex) {

			return null;
		} finally {
			response2.close();
		}
		return response;
	}

	/**
	 * 将NameValuePairs数组转变为字符串
	 * 
	 * @param nameValues
	 * @return
	 */
	protected String toString(NameValuePair[] nameValues) {
		if (nameValues == null || nameValues.length == 0) {
			return "null";
		}

		StringBuffer buffer = new StringBuffer();

		for (int i = 0; i < nameValues.length; i++) {
			NameValuePair nameValue = nameValues[i];

			if (i == 0) {
				buffer.append(nameValue.getName() + "=" + nameValue.getValue());
			} else {
				buffer.append("&" + nameValue.getName() + "=" + nameValue.getValue());
			}
		}

		return buffer.toString();
	}
}
